from ipaddress import IPv4Network

from django.conf import settings
from django.core.exceptions import ValidationError
from django.shortcuts import render, redirect
from django.urls import re_path

from stark.service.v1 import StarkHandler, StarkModelForm
from web import models
from web.utils import ipv4_tools


class IpSubnetPlanModelForm(StarkModelForm):
    class Meta:
        model = models.IpSubnet
        fields = ['subnet', ]

    def clean_subnet(self):
        subnet = self.cleaned_data['subnet']
        try:
            IPv4Network(subnet)
        except:
            raise ValidationError('你输入的网络地址不正确，请重新输入,网络地址示例:192.168.0.0/16')
        return subnet


class IpSubnetPlanHandler(StarkHandler):
    list_display = ['subnet', 'pid']

    model_form_class = IpSubnetPlanModelForm

    def get_urls(self):
        """
        二次路由分发
        :return:
        """
        patterns = [
            re_path(r'^list/(?P<subnet_id>\d+)/$', self.wrapper(self.list_view), name=self.get_list_url_name),
            re_path(r'^add/(?P<subnet_id>\d+)/$', self.wrapper(self.add_view), name=self.get_add_url_name),
            # re_path(r'^change/(?P<subnet_id>\d+)/(?P<pk>\d+)/$', self.wrapper(self.change_view),
            #         name=self.get_change_url_name),
            re_path(r'^delete/(?P<subnet_id>\d+)/(?P<pk>\d+)/$', self.wrapper(self.delete_view),
                    name=self.get_delete_url_name)
        ]
        patterns.extend(self.extra_url())
        return patterns

    def get_queryset(self, request, *args, **kwargs):
        subnet_id = kwargs.get('subnet_id')
        return self.model_class.objects.filter(pid_id=subnet_id)

    def add_view(self, request, *args, **kwargs):
        """
        添加页面
        :return:
        """
        model_form_class = self.get_model_class_form(True, request, None, *args, **kwargs)
        if request.method == 'GET':
            form = model_form_class()
            return render(request, self.add_template or 'stark/change.html', {'form': form})
        form = model_form_class(data=request.POST)
        if form.is_valid():
            subnet = form.cleaned_data['subnet']
            form.instance.subnet_num = int(IPv4Network(subnet).network_address)
            subnet_id = kwargs.get('subnet_id')
            parent_subnet = models.IpSubnet.objects.filter(id=subnet_id).first().subnet
            child_subnet_list = [item.subnet for item in models.IpSubnet.objects.filter(pid_id=subnet_id)]
            flag = ipv4_tools.check_valid_subnet(subnet, parent_subnet, child_subnet_list)
            if flag:
                response = self.save(request, form, subnet, False, *args, **kwargs)
                return response or redirect(self.reverse_list_url(*args, **kwargs))
            else:
                form.add_error('subnet', '请正确规划%s的子网' % parent_subnet)
        return render(request, self.add_template or 'stark/change.html', {'form': form})

    def save(self, request, form, subnet, is_update=False, *args, **kwargs):
        subnet_id = kwargs.get('subnet_id')
        ip_network_id = models.IpSubnet.objects.filter(id=subnet_id).first().ip_network_id
        form.instance.ip_network_id = ip_network_id
        form.instance.pid_id = subnet_id
        form.save()

        # 更新主机列表的网络地址、广播地址
        network_address = ipv4_tools.get_network_address(subnet)
        broadcast_address = ipv4_tools.get_broadcast_address(subnet)
        models.Hosts.objects.filter(ip_address=network_address).update(ip_type=settings.NET_ADDR_IP_TYPE)
        models.Hosts.objects.filter(ip_address=broadcast_address).update(ip_type=settings.BROADCAST_ADDR_IP_TYPE)

        # 更新主机列表的子网号
        network_address_num = ipv4_tools.get_network_address(subnet, data_type='int')
        broadcast_address_num = ipv4_tools.get_broadcast_address(subnet, data_type='int')
        ip_subnet_id = form.instance.id
        models.Hosts.objects.filter(ip_address_num__gte=network_address_num,
                                    ip_address_num__lte=broadcast_address_num).update(ip_subnet_id=ip_subnet_id)

    def delete_view(self, request, pk, *args, **kwargs):
        """
        删除页面
        :param request:
        :return:
        """
        origin_url = self.reverse_list_url(*args, **kwargs)
        current_delete_obj = self.get_delete_object(request, pk, *args, **kwargs)
        if not current_delete_obj:
            info = '数据不存在，请重新选择!'
            return render(request, 'stark/hint.html', {'msg': info, 'return_url': origin_url})
        if current_delete_obj.service_type_id != settings.UNUSE_SERVICE_TYPE:
            info = '子网在使用状态,不能删除'
            return render(request, 'stark/hint.html', {'msg': info, 'return_url': origin_url})
        if request.method == 'GET':
            return render(request, self.delete_template or 'stark/delete.html', {'cancel_url': origin_url})

        # 更新主机列表的子网地址
        subnet_pid_id = current_delete_obj.pid_id
        subnet = current_delete_obj.subnet
        models.Hosts.objects.filter(ip_subnet_id=pk).update(ip_subnet_id=subnet_pid_id)

        # 更新主机分配记录得子网ID
        models.HostRecord.objects.filter(ip_subnet_id=pk).update(ip_subnet_id=subnet_pid_id)

        # 更新主机列表的网络地址和广播地址
        network_address = ipv4_tools.get_network_address(subnet)
        broadcast_address = ipv4_tools.get_broadcast_address(subnet)
        models.Hosts.objects.filter(ip_address__in=(network_address, broadcast_address)).update(
            ip_type_id=settings.UNUSE_IP_TYPE)

        # 删除子网
        current_delete_obj.delete()
        return redirect(origin_url)

    def get_list_display(self, request, *args, **kwargs):
        """
        预留列表页面显示字段的钩子函数
        :return:
        """
        value = []
        if self.list_display:
            value.extend(self.list_display)
            value.append(type(self).display_delete)
        return value

    order_list = ['subnet_num', ]
    search_list = ['subnet__contains']

    def get_add_btn(self, request, *args, **kwargs):
        """
        显示添加按钮
        :return:
        """
        if self.has_add_btn:
            return '<a class="btn btn-primary" href="%s">' \
                   '<i class="fa fa-plus-square" aria-hidden="true"></i>子网分割</a>' % self.reverse_add_url(*args,
                                                                                                         **kwargs)
        return None
